--[[
author: @Dwins
post: https://codea.io/talk/discussion/7464/two-player-tank-game
link: https://gist.github.com/Dwiniflin/10c4a478e43b6d1532499df9439d9627
--]]
--# Main
-- Tank


displayMode(FULLSCREEN_NO_BUTTONS)
-- displayMode(OVERLAY)
supportedOrientations(PORTRAIT)
backingMode(RETAINED)
function setup()
    drawTank()
    player1 = Tank(1,vec2(WIDTH/2-200,HEIGHT/2),
                     vec2(100,100),vec2(WIDTH-125,125))
    player2 = Tank(2,vec2(WIDTH/2+200,HEIGHT/2),
                     vec2(WIDTH-100,HEIGHT-100),vec2(125,HEIGHT-125))
    players = {player1,player2}
    colors = {{c1=color(0,0,80),c2=color(0,0,160),
               c3=color(0,0,240),c4=color(0,0,255)},
              {c1=color(80,0,0),c2=color(160,0,0),
               c3=color(240,0,0),c4=color(255,0,0)}}
    back = mesh()
    back.vertices = {vec2(0,0),vec2(WIDTH,0),vec2(WIDTH,HEIGHT),
                     vec2(WIDTH,HEIGHT),vec2(0,HEIGHT),vec2(0,0)}
    local blue,red = color(0,0,80,150),color(80,0,0,150)
    back.colors = {blue,blue,red,red,red,blue}
    back.colors = {red,red,blue,blue,blue,red}
    backImg = image(WIDTH,HEIGHT)
    setContext(backImg)
    -- background(150)
    -- for i = 1,100 do back:draw() end
    setContext()
    pause = false
    
    -- music("Dropbox:Downpour",true)
    music.volume = 0.25
end

function draw()
    -- background(168, 155, 137, 255)
    back:draw()
    -- fill(255,100)
    -- rect(WIDTH/2,HEIGHT/2,WIDTH,HEIGHT)
    
    font("HelveticaNeue-Bold")
    if pause == false then
        pushMatrix()
        noFill()
        stroke(20,0,30,150)
        stroke(50,0,120,150)
        translate(WIDTH/2,HEIGHT/2)
        ellipse(0,0,200)
        if player1.life == 0 then message = "PLAYER2       WINS" end
        if player2.life == 0 then message = "PLAYER1       WINS" end
        if message then
            rotate(-ElapsedTime*10)
            local str = message
            fontSize(40)
            for i = 1,#str do
                fill(20,0,30,255)
                fill(50,0,120,255)
                local char = string.sub(str,i,i)
                local len = textSize(char)
                rotate(-14)
                text(char,0,120)
            end
        end
        popMatrix()
        if message then
            pushMatrix()
            translate(WIDTH/2,HEIGHT/2)
            rotate(ElapsedTime*100)
            fontSize(40)
            text("REPLAY",0,0)
            popMatrix()
        else
            stroke(20,0,30,150)
            fill(20,0,30,150)
            stroke(50,0,120,150)
            fill(50,0,120,150)
            rect(WIDTH/2-20,HEIGHT/2,20,70)
            rect(WIDTH/2+20,HEIGHT/2,20,70)
        end
    else
        fill(20,0,30,255)
        fill(50,0,120,255)
        fontSize(48)
        pushMatrix()
        translate(WIDTH/2,HEIGHT/2)
        rotate(ElapsedTime*100)
        text("QUIT?",0,0)
        popMatrix()
        -- text("QUIT?",WIDTH/2,HEIGHT/2)
        stroke(20,0,30,150)
        stroke(50,0,120,150)
        noFill()
        strokeWidth(5)
        ellipse(WIDTH/2,HEIGHT/2,200)
    end
    
    if pause == false then
        player1:draw()
        player2:draw()
        player1:drawWeapons()
        player2:drawWeapons()
        player2:drawTank()
        player1:drawTank()
        player1:drawExplosions()
        player2:drawExplosions()
        player1:drawJoysticks()
        player2:drawJoysticks()
    end
    
    fade = fade or 0
    if fade > 0 then
        -- background(0)
        noStroke()
        fill(fade/255)
        rect(WIDTH/2,HEIGHT/2,WIDTH,HEIGHT)
        fade = fade - 1 
    end
    
    --[[
    local r,g,b,a
    noStroke()
    stroke(backImg:get(WIDTH/2,HEIGHT/2))
    for i = 1,12 do 
        r,g,b,a = backImg:get((i-1/2)*64,32)
        fill(r,g,b)
        rect((i-1/2)*64,32,64) 
    end
    for i = 1,16 do 
        r,g,b,a = backImg:get(32,(i-1/2)*64)
        fill(r,g,b)
        rect(32,(i-1/2)*64,64) 
    end
    for i = 1,12 do 
        r,g,b,a = backImg:get((i-1/2)*64,HEIGHT-32)
        fill(r,g,b)
        rect((i-1/2)*64,HEIGHT-32,64) 
    end
    for i = 1,16 do 
        r,g,b,a = backImg:get(WIDTH-32,(i-1/2)*64)
        fill(r,g,b)
        rect(WIDTH-32,(i-1/2)*64,64) 
    end
      ]]
end

function touched(touch)
    if touch.state == BEGAN then
        if vec2(touch.x,touch.y):dist(player1.tPos) < 150 then
            player1.tTouch = touch.id end
        if vec2(touch.x,touch.y):dist(player1.cPos) < 150 then
            player1.cTouch = touch.id end
        if vec2(touch.x,touch.y):dist(player2.tPos) < 150 then
            player2.tTouch = touch.id end
        if vec2(touch.x,touch.y):dist(player2.cPos) < 150 then
            player2.cTouch = touch.id end
        if vec2(touch.x,touch.y):dist(vec2(WIDTH/2,HEIGHT/2)) < 100 then
        -- if touch.y > 300 and touch.y < HEIGHT-300 then
            if pause == true then close() else pause = true end
            -- fade = 10
        else
            pause = false
        end
    end
    
    player1:touched(touch)
    player2:touched(touch)
    
    if touch.state == ENDED then
        if touch.id == player1.tTouch then player1.tTouch = nil end
        if touch.id == player1.cTouch then player1.cTouch = nil end
        if touch.id == player2.tTouch then player2.tTouch = nil end
        if touch.id == player2.cTouch then player2.cTouch = nil end
    end
end

function drawTank()
    c1 = color(80)
    c2 = color(160)
    c3 = color(240)
    tank = image(60,60)
    cannon = image(80,80)
    bullet = image(30,20)
    bombOn = image(50,50)
    bombOff = image(50,50)
    rectMode(CENTER)
    setContext(tank)
    stroke(c1)
    fill(c3)
    rect(30,30,50,60)
    strokeWidth(5)
    line(10,0,10,60)
    line(20,0,20,60)
    line(30,0,30,60)
    line(40,0,40,60)
    line(50,0,50,60)
    fill(c2)
    rect(30,30,60,50)
    fill(c3)
    ellipse(30,30,40,40)
    fill(c2)
    setContext(cannon)
    fill(c3)
    rect(40,40,25,40)
    fill(c3)
    rect(60,40,40,20)
    rect(75,40,10,25)
    fill(c2)
    ellipse(40,40,25)
    setContext(bullet)
    fill(c3)
    stroke(c1)
    rect(10,10,20,20)
    ellipse(20,10,20)
    stroke(c3)
    rect(15,10,11)
    setContext(bombOn)
    stroke(c1)
    fill(c3)
    ellipse(25,25,40)
    fill(c2)
    strokeWidth(3)
    pushMatrix()
    translate(25,25)
    for i = 1,8 do
        rotate(360/8)
        ellipse(0,17,10)
    end
    popMatrix()
    setContext(bombOff)
    strokeWidth(5)
    stroke(c1)
    fill(c2)
    ellipse(25,25,40)
    strokeWidth(3)
    pushMatrix()
    translate(25,25)
    for i = 1,8 do
        rotate(360/8)
        ellipse(0,17,10)
    end
    popMatrix()
    setContext()
end


--# Tank
Tank = class()

function Tank:init(player,position,tankPos,cannonPos)
    self.info = player
    self.pos = position
    self.tPos = tankPos
    self.cPos = cannonPos
    self.tAngle = player*180-90
    self.cAngle = player*180-90
    self.tJoy = vec2(0,0)
    self.cJoy = vec2(0,0)
    self.shots = {}
    self.bombs = {}
    self.explode = {}
    self.tScale = 0
    self.cScale = 0
    
    self.bombMax = 2
    self.bombLoad = self.bombMax
    self.shotMax = 5
    self.shotLoad = self.shotMax
    self.shotWait = 0
    self.lifeMax = 100
    self.life = self.lifeMax
    -- parameter.watch("player1.noise")
end

function Tank:draw()
    if self.tScale > 0 then self.tScale = self.tScale - 1 end
    if self.cScale > 0 then self.cScale = self.cScale - 1 end
    local tAngle = vec2(1,0):angleBetween(self.tJoy)*180/math.pi
    if self.tJoy ~= vec2(0,0) then
        if tAngle > self.tAngle + 180 then self.tAngle = self.tAngle + 360 end
        if tAngle < self.tAngle - 180 then self.tAngle = self.tAngle - 360 end
        self.tAngle = self.tAngle + (tAngle-self.tAngle)/30
        local tVec = vec2(1,0):rotate(math.rad(self.tAngle))
        self.pos = self.pos + tVec*self.tJoy:len()/10*(1+math.random(-3,3)/9)
        sound(SOUND_HIT, 23945, 0.25)
    end
    local cAngle = vec2(1,0):angleBetween(self.cJoy)*180/math.pi
    if self.cJoy ~= vec2(0,0) then
        if cAngle > self.cAngle + 180 then self.cAngle = self.cAngle + 360 end
        if cAngle < self.cAngle - 180 then self.cAngle = self.cAngle - 360 end
        self.cAngle = self.cAngle + (cAngle-self.cAngle)/5
        -- if self.noise then sound(SOUND_HIT, 23960, 0.25) end
        -- if self.noise then sound(SOUND_HIT, 23962, 0.25) end
        if self.noise and self.tJoy == vec2(0,0) then 
            sound(SOUND_HIT, 23945, 0.25) end
    end
    if self.pos.x < 30 then self.pos.x = 30 end
    if self.pos.y < 30 then self.pos.y = 30 end
    if self.pos.x > WIDTH-30 then self.pos.x = WIDTH-30 end
    if self.pos.y > HEIGHT-30 then self.pos.y = HEIGHT-30 end
    local p 
    if self == player1 then p = player2 else p = player1 end
    if self.pos:dist(p.pos) < 60 then
        local vec = self.pos-p.pos
        self.pos = self.pos + vec:normalize()*120/self.pos:dist(p.pos)
    end
    
    self.shotWait = self.shotWait - DeltaTime
    if self.shotWait < 0 then self.shotWait = 0 end
    if self.shotWait == 0 then 
        self.shotLoad = self.shotLoad + DeltaTime*10
    end
    self.bombLoad = self.bombLoad + DeltaTime/3
    if self.shotLoad > self.shotMax then self.shotLoad = self.shotMax end
    if self.bombLoad > self.bombMax then self.bombLoad = self.bombMax end
    if self.life < 0 then self.life = 0 end
end
    
function Tank:drawTank()
    local col = colors[self.info]
    tint(col.c4)
    pushMatrix()
    translate(self.pos.x,self.pos.y)
    pushMatrix()
    rotate(self.tAngle)
    scale(1+self.tScale/20)
    sprite(tank,0,0)
    popMatrix()
    pushMatrix()
    rotate(self.cAngle)
    scale(1+self.cScale/10)
    sprite(cannon,0,0)
    popMatrix()
    popMatrix()
end
    

    
function Tank:drawJoysticks()
    local col = colors[self.info]
    strokeWidth(5)
    stroke(col.c1.r,col.c1.g,col.c1.b)
    fill(col.c2.r,col.c2.g,col.c2.b,100)
    ellipse(self.tPos.x,self.tPos.y,150)
    ellipse(self.cPos.x,self.cPos.y,200)
    fill(col.c3.r,col.c3.g,col.c3.b,150)
    local tj,cj = self.tJoy,self.cJoy
    ellipse(self.tPos.x+self.tJoy.x,self.tPos.y+self.tJoy.y,90)
    ellipse(self.cPos.x+self.cJoy.x,self.cPos.y+self.cJoy.y,120)
    pushStyle()
    pushMatrix()
    tint(col.c4)
    if self == player2 then 
        translate(WIDTH,HEIGHT)
        rotate(180)
    end
    local b = self.bombMax-math.floor(self.bombLoad)
    local b = math.floor(self.bombLoad)
    if b > 0 then
        for i = 1,b do
            fill(col.c2.r,col.c2.g,col.c2.b,100)
            stroke(col.c1)
            rect(50,180+i*50,50)
            sprite(bombOn,50,180+i*50,40)
        end
    end
    local s = self.shotMax-math.floor(self.shotLoad)
    local s = math.floor(self.shotLoad)
    if s > 0 then
        for i = 1,s do
            fill(col.c2.r,col.c2.g,col.c2.b,100)
            stroke(col.c1)
            rect(WIDTH-50,230+i*50,50)
            sprite(bullet,WIDTH-50,230+i*50,-bullet.width)
        end
    end
    local lifeBar = WIDTH-450
    local life = math.ceil(self.life/self.lifeMax*10)
    local s = lifeBar/10
    for i = 1,10 do
        local x,y = (i-1/2)*s,50
        if i > life then fill(col.c1.r,col.c1.g,col.c1.b,100) else             
            fill(col.c3.r,col.c3.g,col.c3.b,150) end
        stroke(col.c1)
        rect(205+x,y,s-2,50)
    end
    popMatrix()
    popStyle()
end

function Tank:touched(touch)
    if touch.id == self.tTouch then
        if touch.state ~= BEGAN then
            local vec = vec2(touch.x,touch.y)-self.tPos
            local angle = vec2(1,0):angleBetween(vec)*180/math.pi
            if vec:len() > 30 then
                self.tJoy = vec:normalize()*30
            else
                self.tJoy = vec
            end
            if touch.state == ENDED then 
                self.tJoy = vec2(0,0) 
                if touch.tapCount > 0 and math.floor(self.bombLoad) > 0 then
                    local pos = self.pos
                    table.insert(self.bombs,
                    {x=pos.x,y=pos.y,c=5})
                    self.tScale = 5
                    self.bombLoad = math.floor(self.bombLoad) - 1
                    sound(SOUND_SHOOT, 23981)
                end
            end
        else
            
        end
    end
    if touch.id == self.cTouch then
        if touch.x ~= touch.prevX and touch.y ~= touch.prevY then 
            self.noise = true 
        else 
            self.noise = false
        end
        local vec = vec2(touch.x,touch.y)-self.cPos
        local angle = vec2(1,0):angleBetween(vec)*180/math.pi
        if vec:len() > 40 then
            self.cJoy = vec:normalize()*40
        else
            self.cJoy = vec
        end
        if touch.state == ENDED then 
            self.cJoy = vec2(0,0) 
            if touch.tapCount > 0 and math.floor(self.shotLoad) > 0 then
                local pos = vec2(50,0):rotate(math.rad(self.cAngle))+self.pos
                table.insert(self.shots,
                {x=pos.x,y=pos.y,a=self.cAngle,deflect=true})
                self.cScale = 5
                self.shotLoad = math.floor(self.shotLoad) - 1
                -- if self.shotLoad == 0 then self.shotLoad = -2 end
                self.shotWait = 1
                self.pos = self.pos - vec2(3,0):rotate(math.rad(self.cAngle))
                self.tAngle = self.tAngle + (math.random(-3,3))
                -- sound(SOUND_SHOOT, 23857)
                -- sound(SOUND_SHOOT, 23858)
                -- sound(SOUND_RANDOM, 23869)
                sound(SOUND_EXPLODE, 23861)
                -- sound(SOUND_EXPLODE, 23866)
                -- sound(SOUND_EXPLODE, 23869)
                -- sound(SOUND_EXPLODE, 23907)
            end
        end
    end
end

--# Attack
function Tank:drawWeapons()
    local col = colors[self.info]
    tint(col.c4)
    for i,s in pairs(self.shots) do
        local vec = vec2(10,0):rotate(math.rad(s.a))
        s.x = s.x + vec.x
        s.y = s.y + vec.y
        pushMatrix()
        translate(s.x,s.y)
        rotate(s.a)
        sprite(bullet)
        popMatrix()
        if s.x < 0 or s.x > WIDTH or s.y < 0 or s.y > HEIGHT then
            if s.deflect == true then
                if s.x < 0 then
                    s.x = 0
                    s.a = 180-s.a
                end
                if s.x > WIDTH then
                    s.x = WIDTH
                    s.a = 180-s.a
                end
                if s.y < 0 then
                    s.y = 0
                    s.a = -s.a
                end
                if s.y > HEIGHT then
                    s.y = HEIGHT
                    s.a = -s.a
                end
                s.deflect = false
                sound(SOUND_SHOOT, 23974)
            else
                table.insert(self.explode,{x=s.x,y=s.y,tab={},c=1/20,mag=10})
                -- s = nil
                table.remove(self.shots,i)
                sound(SOUND_EXPLODE, 25872)
                -- break
            end
        end
        for player = 1,#players do
            local p =  players[player]
            -- if self ~= p 
            if vec2(s.x,s.y):dist(vec2(p.pos.x,p.pos.y)) < 50 then
                p.tAngle = p.tAngle + math.random(-3,3)*10
                p.pos = p.pos + vec2(10,0):rotate(math.rad(s.a))
                -- table.remove(self.shots,i)
                table.insert(self.explode,{x=s.x,y=s.y,tab={},c=1/10,mag=20})
                -- s = nil
                table.remove(self.shots,i)
                sound(SOUND_EXPLODE, 23907)
                -- break
            end
            for v,shot in pairs(p.shots) do
                if s ~= shot 
                and vec2(s.x,s.y):dist(vec2(shot.x,shot.y)) < 15 then
                    -- table.remove(self.shots,i)
                    -- table.remove(p.shots,v)
                    table.insert(self.explode,
                    {x=s.x,y=s.y,tab={},c=1/20,mag=10})
                    -- s = nil
                    -- shot = nil
                    table.remove(p.shots,v)
                    table.remove(self.shots,i)
                    sound(SOUND_HIT, 23966)
                    -- break
                end
            end
            for b,bomb in pairs(p.bombs) do
                if vec2(s.x,s.y):dist(vec2(bomb.x,bomb.y)) < 30 then
                    -- table.remove(self.shots,i)
                    -- table.remove(p.bombs,b)
                    table.insert(self.explode,
                    {x=s.x,y=s.y,tab={},c=1,mag=50})
                    -- s = nil
                    -- bomb = nil
                    table.remove(self.shots,i)
                    table.remove(p.bombs,b)
                    -- sound(SOUND_EXPLODE, 23866)
                        -- sound(SOUND_EXPLODE, 33964)
                    
                    -- break
                end
            end
        end
    end
    for i,b in pairs(self.bombs) do
        local blink
        b.c = b.c - DeltaTime
        if b.c > 2 then
            if math.floor(b.c*2)%2 == 0 then blink = true
            else blink = false end
        else
            if math.floor(b.c*6)%2 == 0 then blink = true
            else blink = false end
        end
        pushMatrix()
        translate(b.x,b.y)
        if blink == true then
            sprite(bombOn,0,0)
        else
            sprite(bombOff,0,0)
        end
        popMatrix()
        if b.c < 0 then 
            -- table.remove(self.bombs,i) 
            table.insert(self.explode,{x=b.x,y=b.y,tab={},c=1,mag=50})
            -- b = nil
            table.remove(self.bombs,i) 
            -- sound(SOUND_RANDOM, 23886) -- This is so cool!
            -- sound(SOUND_EXPLODE, 23866) -- This one too
            -- sound(SOUND_RANDOM, 23942)
            -- sound(SOUND_RANDOM, 23963)
            -- break
        end
        for player = 1,#players do
            local p =  players[player]
            if self ~= p 
            and vec2(b.x,b.y):dist(vec2(p.pos.x,p.pos.y)) < 50 then
                table.remove(self.bombs,i)
                table.insert(self.explode,{x=b.x,y=b.y,tab={},c=1,mag=50})
                -- sound(SOUND_EXPLODE, 23907)
                -- break
            end
        end
    end
end

function Tank:drawExplosions()
    local col = colors[self.info]
    for i,e in pairs(self.explode) do
        if math.ceil(e.c*50)%7 == 0 
        and e.mag >= 30 then sound(SOUND_EXPLODE, 23907) end
        e.c = e.c - DeltaTime
        local r = math.random(1,1)
        if e.c > 0 and r == 1 then
            local x,y = math.huge,math.huge
            while math.sqrt(x^2+y^2) > e.mag do
                x = math.random(-e.mag,e.mag)
                y = math.random(-e.mag,e.mag)
            end
            -- print(e.mag)
            table.insert(e.tab,
            {x=e.x+x,y=e.y+y,
            s=math.random(50,80+e.mag*2)})
            -- sound(SOUND_EXPLODE, 33964)
            -- if e.mag == 30 then sound(SOUND_EXPLODE, 34038) end
            -- if e.mag == 30 then sound(SOUND_EXPLODE, 23907) end
        end
        for t,v in pairs(e.tab) do
            v.s = v.s - 5
            if v.s < 0 then v.s = 0 end
            pushMatrix()
            translate(v.x,v.y)
            --[[
            stroke(colors[self.info].c1)
            strokeWidth(20)
            fill(colors[self.info].c3)
            ellipse(0,0,v.s)
            stroke(colors[self.info].c2)
            ellipse(0,0,v.s/2)
              ]]
            local num = math.random(1,2)
            stroke(colors[num].c1)
            strokeWidth(20)
            fill(colors[num].c3)
            ellipse(0,0,v.s)
            stroke(colors[num].c2)
            ellipse(0,0,v.s/2)
            popMatrix()
            if v.s == 0 then table.remove(e.tab,t) end
            -- if v.s == 0 then v = nil end
        end
        if #e.tab == 0 then
            table.remove(self.explode,i)
            -- e = nil
        end
        for player = 1,#players do
            local p = players[player]
            -- if self ~= p
            if vec2(e.x,e.y):dist(vec2(p.pos.x,p.pos.y)) < 50 + e.mag*2 then
                p.tAngle = p.tAngle + math.random(-3,3)
                -- p.pos = p.pos + vec2(10,0):rotate(math.rad(s.a))
                local vec = p.pos-vec2(e.x,e.y)
                if vec == vec2(0,0) then vec = vec2(1,0) end
                vec = vec:normalize()
                p.pos = p.pos + vec/10
                -- table.remove(self.shots,i)
                -- table.insert(self.explode,{x=e.x,y=e.y,tab={},c=1/10,mag=30})
                -- s = nil
                -- table.remove(self.shots,i)
                if e.mag >= 30 then
                    p.life = p.life - e.mag/200
                else
                    p.life = p.life - e.mag/300
                end
                -- break
            end
        end
    end
end